package org.seedltd.upms.service.impl.sys;

import java.io.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.seedltd.base.exception.BusinessException;
import org.seedltd.core.base.BaseServiceImpl;
import org.seedltd.core.utils.StringUtils;
import org.seedltd.oss.service.IOssService;
import org.seedltd.upms.constant.FolderBucket;
import org.seedltd.upms.enums.EnableStatus;
import org.seedltd.upms.mapper.sys.SysAttachmentMapper;
import org.seedltd.upms.model.sys.entity.SysAttachment;
import org.seedltd.upms.model.sys.vo.SysAttachmentVO;
import org.seedltd.upms.service.sys.SysAttachmentService;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import com.google.common.collect.Lists;

import lombok.AllArgsConstructor;

/**
 * 附件管理带缓存的业务实现
 * 
 * @author laizuan
 * @since 2021/07/30
 * @version 1.0
 */
@Service
@AllArgsConstructor
@CacheConfig(cacheNames = "SysAttachment")
public class SysAttachmentServiceImpl extends BaseServiceImpl<SysAttachmentMapper, SysAttachment>
    implements SysAttachmentService {
    private final SysAttachmentMapper sysAttachmentMapper;
    private final IOssService ossService;

    @Override
    public SysAttachment findById(Serializable id) {
        return sysAttachmentMapper.selectById(id);
    }

    private void deleteFile(SysAttachment sysAttachment) {
        String bucket = sysAttachment.getBucket();
        FolderBucket buckName = FolderBucket.getByBuckName(bucket);
        String path = sysAttachment.getPath();
        try {
            ossService.delete(buckName, path);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
    }

    @Override
    @CacheEvict(key = "#linkedId")
    public boolean delete(Long id, Long linkedId, boolean removeById) {
        if (removeById) {
            SysAttachment sysAttachment = this.findById(id);
            boolean success = u().deleteById(id);
            if (success) {
                deleteFile(sysAttachment);
            }
            return success;
        }
        Map<String, Object> map = new HashMap<>(2);
        map.put("linked_id", linkedId);

        List<SysAttachment> sysAttachments = sysAttachmentMapper.selectByMap(map);
        boolean success = sysAttachmentMapper.deleteByMap(map) > 0;
        if (success) {
            for (SysAttachment sysAttachment : sysAttachments) {
                deleteFile(sysAttachment);
            }
        }

        return success;
    }

    @Override
    public boolean addBatch(MultipartFile[] files, Long linkedId, String bucket) throws IOException {
        return addBatch(files, linkedId, bucket, null);
    }

    @Override
    public boolean addBatch(File[] files, Long linkedId, String bucket) throws IOException {
        return addBatch(files, linkedId, bucket, null);
    }

    @Override
    public boolean addBatch(File[] files, Long linkedId, String bucket, String additional) throws IOException {
        FolderBucket folderBucket = getFolderBucket(files, bucket);
        if (folderBucket == null) {
            return false;
        }

        List<SysAttachment> sysAttachmentList = Lists.newArrayListWithExpectedSize(files.length);
        int i = 0;
        for (File file : files) {
            long size = file.length();
            String originalFilename = file.getName();
            InputStream inputStream = new FileInputStream(file);
            String name = linkedId + originalFilename;
            SysAttachment sysAttachment = getSysAttachment(linkedId, bucket, additional, folderBucket, ++i, size,
                originalFilename, inputStream, name);
            sysAttachmentList.add(sysAttachment);
        }
        return this.saveBatch(sysAttachmentList);
    }

    @Override
    public Long add(File file, Long linkedId, String bucket, String additional) throws IOException {
        FolderBucket folderBucket = check(bucket, file);
        if (folderBucket == null) {
            return null;
        }
        String fileName = file.getName();
        String name = linkedId + fileName;
        SysAttachment sysAttachment = getSysAttachment(linkedId, bucket, additional, folderBucket, 1, file.length(),
            fileName, new FileInputStream(file), name);
        this.save(sysAttachment);
        return sysAttachment.getId();
    }

    @Override
    public Long add(MultipartFile file, Long linkedId, String bucket, String additional) throws IOException {
        if (file == null) {
            return null;
        }

        FolderBucket folderBucket = check(bucket, file);
        if (folderBucket == null) {
            return null;
        }
        String fileName = file.getOriginalFilename();
        String name = linkedId + fileName;
        SysAttachment sysAttachment = getSysAttachment(linkedId, bucket, additional, folderBucket, 1, file.getSize(),
            fileName, file.getInputStream(), name);
        this.save(sysAttachment);
        return sysAttachment.getId();
    }

    private FolderBucket check(String bucket, Object b) {
        if (b == null) {
            return null;
        }

        FolderBucket folderBucket = FolderBucket.getByBuckName(bucket);
        if (folderBucket == null) {
            throw new BusinessException(String.format("桶名【%s】无效", bucket));
        }
        return folderBucket;
    }

    @Override
    public Long add(MultipartFile file, Long linkedId, String bucket) throws IOException {
        return add(file, linkedId, bucket, null);
    }

    @Override
    public Long add(File file, Long linkedId, String bucket) throws IOException {
        return add(file, linkedId, bucket, null);
    }

    @Override
    public boolean addBatch(MultipartFile[] files, Long linkedId, String bucket, String additional) throws IOException {
        if (files == null || files.length == 0) {
            return false;
        }

        FolderBucket folderBucket = getFolderBucket(files, bucket);
        if (folderBucket == null) {
            return false;
        }

        List<SysAttachment> sysAttachmentList = Lists.newArrayListWithExpectedSize(files.length);
        int i = 0;
        for (MultipartFile file : files) {
            long size = file.getSize();
            String originalFilename = file.getOriginalFilename();
            InputStream inputStream = file.getInputStream();
            String name = linkedId + originalFilename;
            SysAttachment sysAttachment = getSysAttachment(linkedId, bucket, additional, folderBucket, ++i, size,
                originalFilename, inputStream, name);
            sysAttachmentList.add(sysAttachment);
        }
        return this.saveBatch(sysAttachmentList);
    }

    private FolderBucket getFolderBucket(Object[] files, String bucket) {
        return check(bucket, files == null || files.length == 0);
    }

    private SysAttachment getSysAttachment(Long linkedId, String bucket, String additional, FolderBucket folderBucket,
        int i, long size, String originalFilename, InputStream inputStream, String name) throws IOException {
        String path = ossService.upload(folderBucket, name, inputStream);

        SysAttachment sysAttachment = new SysAttachment();
        sysAttachment.setPath(path);
        sysAttachment.setLinkedId(linkedId);
        sysAttachment.setFileName(originalFilename);
        sysAttachment.setNewFileName(name);
        int index = StringUtils.lastIndexOf(originalFilename, ".");
        String fileExt = null;
        if (index >= 0) {
            fileExt = originalFilename.substring(index);
        }
        sysAttachment.setFileExt(fileExt);
        sysAttachment.setFileSize(size);
        sysAttachment.setAdditional(additional);
        sysAttachment.setSortNo(i);
        sysAttachment.setBucket(bucket);
        sysAttachment.setEnabled(EnableStatus.ENABLE);
        return sysAttachment;
    }

    @Override
    public Long add(Long linkedId, String bucket, String path, String fileName, String newFileName, String fileExt,
        Long fileSize, String additional, Integer sortNo, EnableStatus enabled, String remark) {
        SysAttachment sysAttachment = new SysAttachment();
        sysAttachment.setPath(path);
        sysAttachment.setLinkedId(linkedId);
        sysAttachment.setFileName(fileName);
        sysAttachment.setNewFileName(newFileName);
        sysAttachment.setFileExt(fileExt);
        sysAttachment.setFileSize(fileSize);
        sysAttachment.setAdditional(additional);
        sysAttachment.setSortNo(sortNo);
        sysAttachment.setBucket(bucket);
        sysAttachment.setEnabled(enabled);
        sysAttachment.setRemark(remark);
        sysAttachmentMapper.insert(sysAttachment);
        return sysAttachment.getId();
    }

    @Override
    public Long add(Long linkedId, String bucket, String path, String fileName, String newFileName, String fileExt,
        Long fileSize, String additional) {
        return add(linkedId, bucket, path, fileName, newFileName, fileExt, fileSize, additional, 0, EnableStatus.ENABLE,
            null);
    }

    @Override
    public Long add(Long linkedId, String bucket, String path, String fileName, String newFileName, Long fileSize) {
        int index = StringUtils.lastIndexOf(fileName, ".");
        String fileExt = null;
        if (index >= 0) {
            fileExt = fileName.substring(index);
        }
        return add(linkedId, bucket, path, fileName, newFileName, fileExt, fileSize, null);
    }

    @Override
    @Cacheable(key = "#linkedId", unless = "#result == null || #result.size() == 0")
    public List<SysAttachmentVO> listByLinkedId(Long linkedId) {
        return q()
            .select(SysAttachment::getId, SysAttachment::getFileExt, SysAttachment::getFileName,
                SysAttachment::getFileSize, SysAttachment::getPath, SysAttachment::getBucket)
            .eq(SysAttachment::getLinkedId, linkedId).orderByDesc(SysAttachment::getSortNo)
            .orderByDesc(SysAttachment::getCreateTime).selectList(SysAttachmentVO.class);
    }
}